﻿namespace TNet
{
    using System;
    using System.IO;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Threading;

    public class SPVPLobbyServer : LobbyServer
    {
        private const int MAX_RESPONSEJOINSEND_TIMES = 5;
        private TNet.Buffer mBuffer;
        private IPEndPoint mCurHostIp;
        private bool mCurResponseAccept;
        private int mCurResponseJoinSendTimes;
        private List<InviteData> mInviteGSList = new List<InviteData>();
        private ServerList.Entry mIpEnt = new ServerList.Entry();
        private long mNextResponseJoinSend;
        private Thread mThread;
        private long mTime;
        private UdpProtocol mUdp;
        public OnInviteRequest onInviteRequest;
        private const long RESPONSEJOIN_TIME = 0x7d0L;

        public override void AddServer(string name, int playerCount, IPEndPoint internalAddress, IPEndPoint externalAddress)
        {
        }

        protected BinaryWriter BeginSend(SPacket packet)
        {
            this.mBuffer = TNet.Buffer.Create();
            return this.mBuffer.BeginPacket((byte) packet);
        }

        protected void EndSend(IPEndPoint ip)
        {
            this.mBuffer.EndPacket();
            this.mUdp.Send(this.mBuffer, ip);
            this.mBuffer.Recycle();
            this.mBuffer = null;
        }

        private bool ProcessPacket(TNet.Buffer buffer, IPEndPoint ip)
        {
            BinaryReader reader = buffer.BeginReading();
            switch (reader.ReadByte())
            {
                case 0x41:
                    if (reader.ReadUInt16() == 0x3600)
                    {
                        ServerList.Entry mIpEnt = this.mIpEnt;
                        lock (mIpEnt)
                        {
                            this.mIpEnt.WriteTo(this.BeginSend(SPacket.ResponseIp));
                        }
                        this.EndSend(ip);
                        return true;
                    }
                    return false;

                case 0x43:
                    if (reader.ReadUInt16() == 0x3600)
                    {
                        ServerList.Entry e = new ServerList.Entry();
                        e.ReadFrom(reader);
                        e.externalAddress = ip;
                        e.recordTime = this.mTime;
                        string k = reader.ReadString();
                        List<InviteData> mInviteGSList = this.mInviteGSList;
                        lock (mInviteGSList)
                        {
                            int size = this.mInviteGSList.size;
                            bool flag = false;
                            for (int i = 0; i < size; i++)
                            {
                                InviteData data = this.mInviteGSList[i];
                                if (data.ipEnt.internalAddress.Equals(e.internalAddress))
                                {
                                    data.ipEnt.name = e.name;
                                    data.ipEnt.playerCount = e.playerCount;
                                    data.key = k;
                                    this.mInviteGSList[i] = data;
                                    flag = true;
                                    break;
                                }
                            }
                            if (!flag)
                            {
                                InviteData item = new InviteData(e, k);
                                this.mInviteGSList.Add(item);
                            }
                        }
                        this.BeginSend(SPacket.ResponseJoin);
                        this.EndSend(ip);
                        return true;
                    }
                    return false;

                case 70:
                    this.mCurHostIp = null;
                    this.mCurResponseAccept = false;
                    this.mCurResponseJoinSendTimes = 0;
                    return true;
            }
            return false;
        }

        public InviteData[] PullInviteGSList()
        {
            InviteData[] dataArray = null;
            List<InviteData> mInviteGSList = this.mInviteGSList;
            lock (mInviteGSList)
            {
                int size = this.mInviteGSList.size;
                if (size <= 0)
                {
                    return dataArray;
                }
                dataArray = new InviteData[size];
                for (int i = 0; i < size; i++)
                {
                    dataArray[i] = this.mInviteGSList[i];
                }
                this.mInviteGSList.Clear();
            }
            return dataArray;
        }

        public override void RemoveServer(IPEndPoint internalAddress, IPEndPoint externalAddress)
        {
        }

        public override bool Start(int listenPort)
        {
            this.Stop();
            this.mUdp = new UdpProtocol();
            if (!this.mUdp.Start(listenPort))
            {
                return false;
            }
            if (string.IsNullOrEmpty(this.mIpEnt.name))
            {
                this.mIpEnt.name = "Default";
            }
            this.mThread = new Thread(new ThreadStart(this.ThreadFunction));
            this.mThread.Start();
            return true;
        }

        public override void Stop()
        {
            if (this.mThread != null)
            {
                this.mThread.Abort();
                this.mThread = null;
            }
            if (this.mUdp != null)
            {
                this.mUdp.Stop();
                this.mUdp = null;
            }
        }

        private void ThreadFunction()
        {
            this.mIpEnt.internalAddress = new IPEndPoint(Tools.localAddress, this.mUdp.listeningPort);
            this.mIpEnt.externalAddress = new IPEndPoint(Tools.localAddress, this.mUdp.listeningPort);
            while (true)
            {
                TNet.Buffer buffer;
                IPEndPoint point;
                this.mTime = DateTime.UtcNow.Ticks / 0x2710L;
                while (((this.mUdp != null) && (this.mUdp.listeningPort != 0)) && this.mUdp.ReceivePacket(out buffer, out point))
                {
                    try
                    {
                        this.ProcessPacket(buffer, point);
                    }
                    catch (Exception)
                    {
                    }
                    if (buffer != null)
                    {
                        buffer.Recycle();
                        buffer = null;
                    }
                }
                if (((this.mNextResponseJoinSend < this.mTime) && (this.mUdp != null)) && (this.mCurHostIp != null))
                {
                    if (this.mCurResponseJoinSendTimes < 5)
                    {
                        TNet.Buffer buffer2 = TNet.Buffer.Create();
                        BinaryWriter bw = buffer2.BeginPacket((byte) 0x45);
                        bw.Write((ushort) 0x3600);
                        if (this.mCurResponseAccept)
                        {
                            bw.WriteInt(1);
                        }
                        else
                        {
                            bw.WriteInt(0);
                        }
                        buffer2.EndPacket();
                        this.mUdp.Send(buffer2, this.mCurHostIp);
                        buffer2.Recycle();
                        buffer2 = null;
                        this.mNextResponseJoinSend = this.mTime + 0x7d0L;
                        this.mCurResponseJoinSendTimes++;
                    }
                    else
                    {
                        this.mCurHostIp = null;
                        this.mCurResponseAccept = false;
                        this.mCurResponseJoinSendTimes = 0;
                    }
                }
                Thread.Sleep(1);
            }
        }

        public void UpdateIpEnt(string name, int playerCount = 0)
        {
            ServerList.Entry mIpEnt = this.mIpEnt;
            lock (mIpEnt)
            {
                this.mIpEnt.name = name;
                this.mIpEnt.playerCount = playerCount;
            }
        }

        public void UserResponseJoin(IPEndPoint hostIp, bool accept)
        {
            this.mCurHostIp = hostIp;
            this.mCurResponseAccept = accept;
            this.mCurResponseJoinSendTimes = 0;
            this.mNextResponseJoinSend = 0L;
        }

        public IPAddress curInternalIP
        {
            get
            {
                if (this.mIpEnt.internalAddress != null)
                {
                    return this.mIpEnt.internalAddress.Address;
                }
                return Tools.localAddress;
            }
        }

        public override bool isActive
        {
            get
            {
                return ((this.mUdp != null) && this.mUdp.isActive);
            }
        }

        public override int port
        {
            get
            {
                return (!this.mUdp.isActive ? 0 : this.mUdp.listeningPort);
            }
        }

        public delegate void OnInviteRequest(ServerList.Entry gsEnt);
    }
}

